package com.nvwa.coding.model;

import com.nvwa.coding.util.safe.Coding;
import lombok.Getter;

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.List;


public class StringTimePeriod extends AbstractTimePeriod<StringTime> {

    @Getter
    protected StringTime start;

    @Getter
    protected StringTime end;

    public static final StringTimePeriod EMPTY = new StringTimePeriod() {
        @Override
        public boolean valid() {
            return false;
        }
    };

    private StringTimePeriod() {

    }

    public StringTimePeriod(StringTime start, StringTime end) {
        this.start = start;
        this.end = end;
        if (valid() && this.start.asLocalTime().isAfter(this.end.asLocalTime())) {
            this.acrossDate = true;
        }
    }

    public StringTimePeriod(String start, String end) {
        this(new StringTime(start), new StringTime(end));
    }

    public static StringTimePeriod from(String period) {
        if (Coding.isBlank(period)) {
            return EMPTY;
        }
        List<String> split = Ensurer.of(Coding.arrayList("", ""), list -> list.size() == 2)
                                    .ensure(
                                            () -> Coding.splitToList(period, "-"),
                                            () -> Coding.splitToList(period, "_"),
                                            () -> Coding.splitToList(period, " "),
                                            () -> Coding.splitToList(period, "~"),
                                            () -> Coding.splitToList(period, ","),
                                            () -> Coding.splitToList(period, ";"),
                                            () -> Coding.splitToList(period, "|")
                                    );
        return new StringTimePeriod(split.get(0), split.get(1));
    }

    @Override
    public boolean inPeriod(StringTime o) {
        return inPeriod(o.asLocalTime());
    }

    public boolean inPeriod(LocalTime localTime) {
        if (localTime == null || notValid()) {
            return false;
        }
        if (acrossDate) {
            return !start.asLocalTime().isAfter(localTime) || !end.asLocalTime().isBefore(localTime);
        }
        return !start.asLocalTime().isAfter(localTime) && !end.asLocalTime().isBefore(localTime);
    }

    public boolean inPeriod(StringDateTime o) {
        return inPeriod(o.onlyTime());
    }

    public boolean nowInPeriod() {
        return inPeriod(LocalTime.now());
    }

    public StringDateTimePeriod withDate(LocalDate localDate) {
        return valid()
               ? isAcrossDate()
                 ? new StringDateTimePeriod(start.withDate(localDate), end.withDate(localDate.plusDays(1)))
                 : new StringDateTimePeriod(start.withDate(localDate), end.withDate(localDate))
               : StringDateTimePeriod.EMPTY;
    }

}
